1   /*                        __    __  __  __    __  ___
2    *                       \  \  /  /    \  \  /  /  __/
3    *                        \  \/  /  /\  \  \/  /  /
4    *                         \____/__/  \__\____/__/.ɪᴏ
5    * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
6    */
7   package io.vavr.collection;
8   
9   import io.vavr.Serializables;
10  import io.vavr.Tuple;
11  import io.vavr.Value;
12  import io.vavr.Tuple2;
13  import io.vavr.control.Option;
14  import org.junit.Test;
15  
16  import java.io.InvalidObjectException;
17  import java.math.BigDecimal;
18  import java.util.ArrayList;
19  import java.util.NoSuchElementException;
20  import java.util.Spliterator;
21  import java.util.function.Function;
22  import java.util.function.Supplier;
23  import java.util.stream.Collector;
24  
25  public class ListTest extends AbstractLinearSeqTest {
26  
27      // -- construction
28  
29      @Override
30      protected <T> Collector<T, ArrayList<T>, List<T>> collector() {
31          return List.collector();
32      }
33  
34      @Override
35      protected <T> List<T> empty() {
36          return List.empty();
37      }
38  
39      @Override
40      protected <T> List<T> of(T element) {
41          return List.of(element);
42      }
43  
44      @SuppressWarnings("varargs")
45      @SafeVarargs
46      @Override
47      protected final <T> List<T> of(T... elements) {
48          return List.of(elements);
49      }
50  
51      @Override
52      protected <T> List<T> ofAll(Iterable<? extends T> elements) {
53          return List.ofAll(elements);
54      }
55  
56      @Override
57      protected <T extends Comparable<? super T>> List<T> ofJavaStream(java.util.stream.Stream<? extends T> javaStream) {
58          return List.ofAll(javaStream);
59      }
60  
61      @Override
62      protected List<Boolean> ofAll(boolean... elements) {
63          return List.ofAll(elements);
64      }
65  
66      @Override
67      protected List<Byte> ofAll(byte... elements) {
68          return List.ofAll(elements);
69      }
70  
71      @Override
72      protected List<Character> ofAll(char... elements) {
73          return List.ofAll(elements);
74      }
75  
76      @Override
77      protected List<Double> ofAll(double... elements) {
78          return List.ofAll(elements);
79      }
80  
81      @Override
82      protected List<Float> ofAll(float... elements) {
83          return List.ofAll(elements);
84      }
85  
86      @Override
87      protected List<Integer> ofAll(int... elements) {
88          return List.ofAll(elements);
89      }
90  
91      @Override
92      protected List<Long> ofAll(long... elements) {
93          return List.ofAll(elements);
94      }
95  
96      @Override
97      protected List<Short> ofAll(short... elements) {
98          return List.ofAll(elements);
99      }
100 
101     @Override
102     protected <T> List<T> tabulate(int n, Function<? super Integer, ? extends T> f) {
103         return List.tabulate(n, f);
104     }
105 
106     @Override
107     protected <T> List<T> fill(int n, Supplier<? extends T> s) {
108         return List.fill(n, s);
109     }
110 
111     @Override
112     protected List<Character> range(char from, char toExclusive) {
113         return List.range(from, toExclusive);
114     }
115 
116     @Override
117     protected List<Character> rangeBy(char from, char toExclusive, int step) {
118         return List.rangeBy(from, toExclusive, step);
119     }
120 
121     @Override
122     protected List<Double> rangeBy(double from, double toExclusive, double step) {
123         return List.rangeBy(from, toExclusive, step);
124     }
125 
126     @Override
127     protected List<Integer> range(int from, int toExclusive) {
128         return List.range(from, toExclusive);
129     }
130 
131     @Override
132     protected List<Integer> rangeBy(int from, int toExclusive, int step) {
133         return List.rangeBy(from, toExclusive, step);
134     }
135 
136     @Override
137     protected List<Long> range(long from, long toExclusive) {
138         return List.range(from, toExclusive);
139     }
140 
141     @Override
142     protected List<Long> rangeBy(long from, long toExclusive, long step) {
143         return List.rangeBy(from, toExclusive, step);
144     }
145 
146     @Override
147     protected List<Character> rangeClosed(char from, char toInclusive) {
148         return List.rangeClosed(from, toInclusive);
149     }
150 
151     @Override
152     protected List<Character> rangeClosedBy(char from, char toInclusive, int step) {
153         return List.rangeClosedBy(from, toInclusive, step);
154     }
155 
156     @Override
157     protected List<Double> rangeClosedBy(double from, double toInclusive, double step) {
158         return List.rangeClosedBy(from, toInclusive, step);
159     }
160 
161     @Override
162     protected List<Integer> rangeClosed(int from, int toInclusive) {
163         return List.rangeClosed(from, toInclusive);
164     }
165 
166     @Override
167     protected List<Integer> rangeClosedBy(int from, int toInclusive, int step) {
168         return List.rangeClosedBy(from, toInclusive, step);
169     }
170 
171     @Override
172     protected List<Long> rangeClosed(long from, long toInclusive) {
173         return List.rangeClosed(from, toInclusive);
174     }
175 
176     @Override
177     protected List<Long> rangeClosedBy(long from, long toInclusive, long step) {
178         return List.rangeClosedBy(from, toInclusive, step);
179     }
180 
181     @Override
182     @SuppressWarnings("unchecked")
183     protected <T> List<List<T>> transpose(Seq<? extends Seq<T>> rows) {
184         return List.transpose((List<List<T>>) rows);
185     }
186 
187     @Override
188     protected int getPeekNonNilPerformingAnAction() {
189         return 1;
190     }
191 
192     // -- static narrow
193 
194     @Test
195     public void shouldNarrowList() {
196         final List<Double> doubles = of(1.0d);
197         final List<Number> numbers = List.narrow(doubles);
198         final int actual = numbers.append(new BigDecimal("2.0")).sum().intValue();
199         assertThat(actual).isEqualTo(3);
200     }
201 
202     // -- ofAll(NavigableSet)
203 
204     @Test
205     public void shouldAcceptNavigableSet() {
206         final java.util.TreeSet<Integer> javaSet = new java.util.TreeSet<>();
207         javaSet.add(2);
208         javaSet.add(1);
209         assertThat(List.ofAll(javaSet)).isEqualTo(List.of(1, 2));
210     }
211 
212     // -- peek
213 
214     @Test(expected = NoSuchElementException.class)
215     public void shouldFailPeekOfNil() {
216         empty().peek();
217     }
218 
219     @Test
220     public void shouldPeekOfNonNil() {
221         assertThat(of(1).peek()).isEqualTo(1);
222         assertThat(of(1, 2).peek()).isEqualTo(1);
223     }
224 
225     // -- peekOption
226 
227     @Test
228     public void shouldPeekOption() {
229         assertThat(empty().peekOption()).isSameAs(Option.none());
230         assertThat(of(1).peekOption()).isEqualTo(Option.of(1));
231         assertThat(of(1, 2).peekOption()).isEqualTo(Option.of(1));
232     }
233 
234     // -- pop
235 
236     @Test(expected = NoSuchElementException.class)
237     public void shouldFailPopOfNil() {
238         empty().pop();
239     }
240 
241     @Test
242     public void shouldPopOfNonNil() {
243         assertThat(of(1).pop()).isSameAs(empty());
244         assertThat(of(1, 2).pop()).isEqualTo(of(2));
245     }
246 
247     // -- popOption
248 
249     @Test
250     public void shouldPopOption() {
251         assertThat(empty().popOption()).isSameAs(Option.none());
252         assertThat(of(1).popOption()).isEqualTo(Option.of(empty()));
253         assertThat(of(1, 2).popOption()).isEqualTo(Option.of(of(2)));
254     }
255 
256     // -- pop2
257 
258     @Test(expected = NoSuchElementException.class)
259     public void shouldFailPop2OfNil() {
260         empty().pop2();
261     }
262 
263     @Test
264     public void shouldPop2OfNonNil() {
265         assertThat(of(1).pop2()).isEqualTo(Tuple.of(1, empty()));
266         assertThat(of(1, 2).pop2()).isEqualTo(Tuple.of(1, of(2)));
267     }
268 
269     // -- pop2Option
270 
271     @Test
272     public void shouldPop2Option() {
273         assertThat(empty().pop2Option()).isSameAs(Option.none());
274         assertThat(of(1).pop2Option()).isEqualTo(Option.of(Tuple.of(1, empty())));
275         assertThat(of(1, 2).pop2Option()).isEqualTo(Option.of(Tuple.of(1, of(2))));
276     }
277 
278     // -- push
279 
280     @Test
281     public void shouldPushElements() {
282         assertThat(empty().push(1)).isEqualTo(of(1));
283         assertThat(empty().push(1, 2, 3)).isEqualTo(of(3, 2, 1));
284         assertThat(empty().pushAll(of(1, 2, 3))).isEqualTo(of(3, 2, 1));
285         assertThat(of(0).push(1)).isEqualTo(of(1, 0));
286         assertThat(of(0).push(1, 2, 3)).isEqualTo(of(3, 2, 1, 0));
287         assertThat(of(0).pushAll(of(1, 2, 3))).isEqualTo(of(3, 2, 1, 0));
288     }
289 
290     // -- transform()
291 
292     @Test
293     public void shouldTransform() {
294         final String transformed = of(42).transform(v -> String.valueOf(v.get()));
295         assertThat(transformed).isEqualTo("42");
296     }
297 
298     // -- toString
299 
300     @Test
301     public void shouldStringifyNil() {
302         assertThat(empty().toString()).isEqualTo("List()");
303     }
304 
305     @Test
306     public void shouldStringifyNonNil() {
307         assertThat(of(1, 2, 3).toString()).isEqualTo("List(1, 2, 3)");
308     }
309 
310     // -- unfold
311 
312     @Test
313     public void shouldUnfoldRightToEmpty() {
314         assertThat(List.unfoldRight(0, x -> Option.none())).isEqualTo(empty());
315     }
316 
317     @Test
318     public void shouldUnfoldRightSimpleList() {
319         assertThat(
320                 List.unfoldRight(10, x -> x == 0
321                                           ? Option.none()
322                                           : Option.of(new Tuple2<>(x, x - 1))))
323                 .isEqualTo(of(10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
324     }
325 
326     @Test
327     public void shouldUnfoldLeftToEmpty() {
328         assertThat(List.unfoldLeft(0, x -> Option.none())).isEqualTo(empty());
329     }
330 
331     @Test
332     public void shouldUnfoldLeftSimpleList() {
333         assertThat(
334                 List.unfoldLeft(10, x -> x == 0
335                                          ? Option.none()
336                                          : Option.of(new Tuple2<>(x - 1, x))))
337                 .isEqualTo(of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
338     }
339 
340     @Test
341     public void shouldUnfoldToEmpty() {
342         assertThat(List.unfold(0, x -> Option.none())).isEqualTo(empty());
343     }
344 
345     @Test
346     public void shouldUnfoldSimpleList() {
347         assertThat(
348                 List.unfold(10, x -> x == 0
349                                      ? Option.none()
350                                      : Option.of(new Tuple2<>(x - 1, x))))
351                 .isEqualTo(of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
352     }
353 
354     // -- Cons test
355 
356     @Test(expected = InvalidObjectException.class)
357     public void shouldNotSerializeEnclosingClass() throws Throwable {
358         Serializables.callReadObject(List.of(1));
359     }
360 
361     @Test(expected = InvalidObjectException.class)
362     public void shouldNotDeserializeListWithSizeLessThanOne() throws Throwable {
363         try {
364             /*
365              * This implementation is stable regarding jvm impl changes of object serialization. The index of the number
366              * of List elements is gathered dynamically.
367              */
368             final byte[] listWithOneElement = Serializables.serialize(List.of(0));
369             final byte[] listWithTwoElements = Serializables.serialize(List.of(0, 0));
370             int index = -1;
371             for (int i = 0; i < listWithOneElement.length && index == -1; i++) {
372                 final byte b1 = listWithOneElement[i];
373                 final byte b2 = listWithTwoElements[i];
374                 if (b1 != b2) {
375                     if (b1 != 1 || b2 != 2) {
376                         throw new IllegalStateException("Difference does not indicate number of elements.");
377                     } else {
378                         index = i;
379                     }
380                 }
381             }
382             if (index == -1) {
383                 throw new IllegalStateException("Hack incomplete - index not found");
384             }
385             /*
386              * Hack the serialized data and fake zero elements.
387              */
388             listWithOneElement[index] = 0;
389             Serializables.deserialize(listWithOneElement);
390         } catch (IllegalStateException x) {
391             throw (x.getCause() != null) ? x.getCause() : x;
392         }
393     }
394 
395     @Override
396     protected boolean useIsEqualToInsteadOfIsSameAs() {
397         return false;
398     }
399 
400     // -- toList
401 
402     @Test
403     public void shouldReturnSelfOnConvertToList() {
404         final Value<Integer> value = of(1, 2, 3);
405         assertThat(value.toList()).isSameAs(value);
406     }
407 
408     // -- spliterator
409 
410 
411     @Test
412     public void shouldHaveSizedSpliterator() {
413         assertThat(of(1, 2, 3).spliterator().hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)).isTrue();
414     }
415 
416     @Test
417     public void shouldReturnSizeWhenSpliterator() {
418         assertThat(of(1, 2, 3).spliterator().getExactSizeIfKnown()).isEqualTo(3);
419     }
420 }